package com.pf.utils;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.pf.common.annotation.ManualReminderCheckAccount;
import com.pf.common.annotation.ManualReminderCheckStatus;
import com.pf.common.annotation.ManualReminderCode;
import com.pf.common.exception.BusinessException;
import com.pf.dto.CheckFieldInfoDTO;
import com.pf.dto.ManualReminderReq;
import com.pf.dto.ManualReminderResp;
import com.pf.enums.FieldTypeEnum;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author PanFei
 * @version 1.0.0
 * @createTime 2022/11/21 20:35
 */
public class ManualReminderUtils {

    /**
     * 手动提醒校验
     *
     * @param checkFieldInfoList
     * @param closeStatusList
     * @return
     */
    public static ManualReminderResp manualReminderVerification(List<CheckFieldInfoDTO> checkFieldInfoList, List<String> closeStatusList) {
        if (CollectionUtils.isEmpty(checkFieldInfoList)) {
            return null;
        }
        // 查询工号对应的长短工号信息
        Set<String> accountSet = checkFieldInfoList.stream()
                .filter(item -> FieldTypeEnum.ACCOUNT.equals(item.getFieldType()) && StringUtils.isNotBlank(item.getFieldValue()))
                .map(CheckFieldInfoDTO::getFieldValue).collect(Collectors.toSet());
        System.out.println("accountSet=" + accountSet);
        // 模拟查询对应长短工号
        Map<String, String> accountMapping = ImmutableMap.of("wanger", "wwx wanger", "zhangsan", "zwx zhangsan", "wangwu", "wwx wangwu", "lisi", "lwx lisi");

        // 循环校验非空，离职，状态
        List<ManualReminderResp.FailDetailData> failDetailDataList = Lists.newArrayList();
        Map<Integer, List<CheckFieldInfoDTO>> checkFieldInfoMap = checkFieldInfoList.stream().collect(Collectors.groupingBy(CheckFieldInfoDTO::getRowIndex));
        StringBuilder emptyErrorMsg = new StringBuilder();
        StringBuilder resignedMemberErrorMsg = new StringBuilder();
        StringBuilder closeStatusErrorMsg = new StringBuilder();
        StringBuilder otherErrorMsg = new StringBuilder();
        checkFieldInfoMap.forEach((rowIndex, eachFieldInfoList) -> {
            eachFieldInfoList.forEach(fieldInfo -> {
                // 判断非空
                if (StringUtils.isBlank(fieldInfo.getFieldValue())) {
                    emptyErrorMsg.append("【").append(fieldInfo.getFieldDesc()).append("】").append("、");
                }
                // 判断离职
                if (FieldTypeEnum.ACCOUNT.equals(fieldInfo.getFieldType()) && StringUtils.isNotBlank(fieldInfo.getFieldValue())
                        && accountMapping != null && StringUtils.isBlank(accountMapping.get(fieldInfo.getFieldValue()))) {
                    resignedMemberErrorMsg.append("【").append(fieldInfo.getFieldDesc()).append("】【").append(fieldInfo.getFieldValue()).append("】、");
                }
                // 状态判断
                if (FieldTypeEnum.STATUS.equals(fieldInfo.getFieldType()) && StringUtils.isNotBlank(fieldInfo.getFieldValue()) && closeStatusList.contains(fieldInfo.getFieldValue())) {
                    closeStatusErrorMsg.append("【").append(fieldInfo.getFieldDesc()).append("】").append(fieldInfo.getFieldValue()).append("是关闭状态，不能发送w3或ESpace提醒；");
                }
                // 其他校验
                if (FieldTypeEnum.OTHER.equals(fieldInfo.getFieldType()) && StringUtils.isNotBlank(fieldInfo.getErrorMsg())) {
                    otherErrorMsg.append(fieldInfo.getErrorMsg());
                }
            });
            if (emptyErrorMsg.length() > 0) {
                emptyErrorMsg.deleteCharAt(emptyErrorMsg.length() - 1);
                emptyErrorMsg.append("不能为空；");
            }
            if (resignedMemberErrorMsg.length() > 0) {
                resignedMemberErrorMsg.deleteCharAt(resignedMemberErrorMsg.length() - 1);
                resignedMemberErrorMsg.append("不是w3工号或已离职；");
            }
            if (emptyErrorMsg.length() > 0 || resignedMemberErrorMsg.length() > 0 || otherErrorMsg.length() > 0 || closeStatusErrorMsg.length() > 0) {
                String errorMsg = emptyErrorMsg.toString() + resignedMemberErrorMsg.toString() + otherErrorMsg.toString() + closeStatusErrorMsg.toString();
                ManualReminderResp.FailDetailData failDetailData = ManualReminderResp.FailDetailData.builder().rowIndex(rowIndex).errorMsg(errorMsg).build();
                failDetailDataList.add(failDetailData);
            }
            emptyErrorMsg.setLength(0);
            resignedMemberErrorMsg.setLength(0);
            otherErrorMsg.setLength(0);
            closeStatusErrorMsg.setLength(0);
        });

        int totalCount = checkFieldInfoMap.size();
        int failCount = failDetailDataList.size();
        int successCount = totalCount - failCount;
        ManualReminderResp manualReminderResp = ManualReminderResp.builder().successCount(successCount).failCount(failCount).failDetailData(failDetailDataList).build();
        return manualReminderResp;
    }

    public static <T> ManualReminderResp manualReminderVerification(ManualReminderReq reminderReq, Supplier<List<T>> supplier) {
        List<T> dataList = supplier.get();
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        // 获取含有 @ManualReminderCheck 注解的属性
        Class<?> clazz = dataList.get(0).getClass();
        // 校验并获取 @ManualReminderCode，@ManualReminderCheckStatus，@ManualReminderCheckAccount注解字段
        Map<Class<? extends Annotation>, List<Field>> manualReminderAnnotationMap = getManualReminderAnnotations(clazz);
        List<Field> codeFieldList = manualReminderAnnotationMap.get(ManualReminderCode.class);
        if (CollectionUtils.isEmpty(codeFieldList) || codeFieldList.size() != 1) {
            throw new BusinessException(clazz + "未配置@ManualReminderCode注解或@ManualReminderCode注解只能配置一个");
        }
        List<Field> statusFieldList = manualReminderAnnotationMap.get(ManualReminderCheckStatus.class);
        if (CollectionUtils.isEmpty(statusFieldList) || statusFieldList.size() != 1) {
            throw new BusinessException(clazz + "未配置@ManualReminderCheckStatus注解或@ManualReminderCheckStatus注解只能配置一个");
        }
        List<Field> accountFieldList = manualReminderAnnotationMap.get(ManualReminderCheckAccount.class);
        if (CollectionUtils.isEmpty(accountFieldList)) {
            throw new BusinessException(clazz + "未配置@ManualReminderCheckAccount注解");
        }
        Field codeField = codeFieldList.get(0);
        Field statusField = statusFieldList.get(0);
        // 将请求参数状态map格式，key为业务code，value为序号
        List<ManualReminderReq.RowIndexAndCodeDTO> rowIndexAndCodeList = reminderReq.getRowIndexAndCodeList();
        Map<String, Integer> rowIndexAndCodeMap = rowIndexAndCodeList.stream().collect(Collectors.toMap(ManualReminderReq.RowIndexAndCodeDTO::getCode, ManualReminderReq.RowIndexAndCodeDTO::getRowIndex));

        // 将查询的dataList转为 List<CheckFieldInfoDTO>
        List<CheckFieldInfoDTO> checkFieldInfoList = Lists.newArrayList();
        List<String> closeStatusList = null;
        try {
            for (T obj : dataList) {
                // 获取业务code值对应的序号值
                codeField.setAccessible(true);
                String code = (String) codeField.get(obj);
                Integer rowIndex = rowIndexAndCodeMap.get(code);
                if (rowIndex == null) {
                    throw new BusinessException(clazz + "获取rowIndex值为空！");
                }
                // 获取状态值，并将状态字段转为期望数据格式
                ManualReminderCheckStatus manualReminderCheckStatus = statusField.getAnnotation(ManualReminderCheckStatus.class);
                String[] closeStatusArray = manualReminderCheckStatus.closeStatusArray();
                if (closeStatusArray == null) {
                    throw new BusinessException(clazz + "配置的STATUS属性ManualReminderCheck注解未配置 closeStatusArray！");
                }
                closeStatusList = Arrays.asList(closeStatusArray);
                statusField.setAccessible(true);
                String status = (String) statusField.get(obj);
                CheckFieldInfoDTO statusCheckFieldInfo = CheckFieldInfoDTO.builder()
                        .rowIndex(rowIndex)
                        .fieldType(FieldTypeEnum.STATUS)
                        .fieldDesc(manualReminderCheckStatus.fieldDesc())
                        .fieldValue(status)
                        .build();
                checkFieldInfoList.add(statusCheckFieldInfo);

                // 处理账号字段
                for (Field accountField : accountFieldList) {
                    if (accountField.isAnnotationPresent(ManualReminderCheckAccount.class)) {
                        ManualReminderCheckAccount manualReminderCheckAccount = accountField.getAnnotation(ManualReminderCheckAccount.class);
                        accountField.setAccessible(true);
                        String accountValue = (String) accountField.get(obj);
                        CheckFieldInfoDTO accountCheckFieldInfo = CheckFieldInfoDTO.builder()
                                .rowIndex(rowIndex)
                                .fieldType(FieldTypeEnum.ACCOUNT)
                                .fieldDesc(manualReminderCheckAccount.fieldDesc())
                                .fieldValue(accountValue)
                                .build();
                        checkFieldInfoList.add(accountCheckFieldInfo);
                    }
                }
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (CollectionUtils.isEmpty(closeStatusList)) {
            throw new BusinessException(clazz + "配置的STATUS属性ManualReminderCheck注解未配置 closeStatusArray！");
        }

        return manualReminderVerification(checkFieldInfoList, closeStatusList);
    }

    private static Field getFirstTargetField(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(annotationClass)) {
                return field;
            }
        }
        return null;
    }

    /**
     * 递归获取某类型上还有指定注解的属性
     *
     * @param clazz               目标类型
     * @param annotationClassList 指定注解集合
     * @param fieldList           含有目标注解的属性集合
     */
    private static void getRecursiveFields(Class<?> clazz, List<Class<? extends Annotation>> annotationClassList, List<Field> fieldList) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            for (Class annotationClass : annotationClassList) {
                if (field.isAnnotationPresent(annotationClass)) {
                    fieldList.add(field);
                }
            }
        }
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null && !superclass.equals(Object.class)) {
            getRecursiveFields(superclass, annotationClassList, fieldList);
        }
    }

    private static List<Field> getFields(Class<?> clazz, List<Class<? extends Annotation>> annotationClassList) {
        List<Field> fieldList = Lists.newArrayList();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            for (Class annotationClass : annotationClassList) {
                if (field.isAnnotationPresent(annotationClass)) {
                    fieldList.add(field);
                }
            }
        }
        return fieldList;
    }

    private static Map<Class<? extends Annotation>, List<Field>> getManualReminderAnnotations(Class<?> clazz) {
        Map<Class<? extends Annotation>, List<Field>> map = new HashMap<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(ManualReminderCode.class)) {
                List<Field> codeFieldList = map.get(ManualReminderCode.class);
                if (CollectionUtils.isEmpty(codeFieldList)) {
                    codeFieldList = Lists.newArrayList(field);
                    map.put(ManualReminderCode.class, codeFieldList);
                } else {
                    if (!codeFieldList.contains(field)) {
                        codeFieldList.add(field);
                    }
                }
            }
            if (field.isAnnotationPresent(ManualReminderCheckStatus.class)) {
                List<Field> statusFieldList = map.get(ManualReminderCheckStatus.class);
                if (CollectionUtils.isEmpty(statusFieldList)) {
                    statusFieldList = Lists.newArrayList(field);
                    map.put(ManualReminderCheckStatus.class, statusFieldList);
                } else {
                    if (!statusFieldList.contains(field)) {
                        statusFieldList.add(field);
                    }
                }
            }
            if (field.isAnnotationPresent(ManualReminderCheckAccount.class)) {
                List<Field> accountFieldList = map.get(ManualReminderCheckAccount.class);
                if (CollectionUtils.isEmpty(accountFieldList)) {
                    accountFieldList = Lists.newArrayList(field);
                    map.put(ManualReminderCheckAccount.class, accountFieldList);
                } else {
                    if (!accountFieldList.contains(field)) {
                        accountFieldList.add(field);
                    }
                }
            }
        }
        return map;
    }
}
